package asteroids;
import be.kuleuven.cs.som.annotate.*;


/**
 * 
 * @invar	  The coordinates of each ship must be valid.
 * 			| isValidCoordinate(getXCoordinate) &&
 * 			| isValidCoordinate(getYCoordinate)
 * @invar     The velocity according to the x and y axis must be valid.
 * 			| isValidVelocity(getXVelocity()) && isValidVelocity(getYVelocity)		
 * @invar 	  The total velocity of each ship is less than MAX_SPEED.
 * 		 	| isValidVelocity((Math.sqrt(Math.pow(xVelocity, 2)+Math.pow(yVelocity,2))))
 * @invar 	  The radius of each ship is valid.
 * 		 	| isValidRadius(getRadius);
 * 
 * @version 0.1
 * @author  Tandan Sunil, Van Deun Luca
 *
 */

public class Ship implements IShip{

/**
 * Initialize this new ship with given coordinates and speed according to x- and y- axes, radius and direction.
 *  
 * @param  xCoordinate 
 * 		   The x-coordinate for this new ship in kilometers.
 * @param  yCoordinate
 * 		   The y-coordinate for this new ship in kilometers.
 * @param  xVelocity
 * 		   The initial velocity for this new ship according to the x-axis in kilometers/second.
 * @param  yVelocity
 * 	       The initial velocity for this new ship according to the y-axis in kilometers/second.
 * @param  radius
 * 		   The radius for this new circular ship in kilometers. 
 * @param  angle
 * 		   The initial direction for this new ship in radians (0 = east, Pi/2 = north, Pi = west, 3*Pi/2 = south). 
 * @pre	   The given radius must be a valid radius for a ship.
 * 		 | isValidRadius(radius)
 * @pre	   The total speed of this new ship must be valid.
 * 	 	 | isValidVelocity((Math.sqrt(Math.pow(xVelocity, 2)+Math.pow(yVelocity,2)))) 
 * @pre    The angle of this new ship must be valid.
 * 		 | isValidAngle(angle)
 * @post   The new ship has the given x-coordinate.
 * 		 | new.getXCoordinate() == xCoordinate
 * @post   The new ship has the given y-coordinate.
 * 		 | new.getYCoordinate() == yCoordinate
 * @post   The new ship has the given radius.
 * 		 | new.getRadius() == radius
 * @post   The new ship has the given angle.
 * 		 | new.getAngle() == angle
 * @effect The given velocities are set as the new velocities of this new ship.
 * 		 | setVelocity(xVelocity,yVelocity)
 * @throws IllegalArgumentException
 * 		   The given radius is invalid.
 * 		 | ! isValidRadius(radius)
 * @throws IllegalArgumentException
 * 		   The given coordinate is invalid.
 * 		 | ! isValidCoordinate(xCoordinate) || ! isValidCoordinate(yCoordinate)
 *
 */
public Ship(double xCoordinate, double yCoordinate, double xVelocity,
		double yVelocity, double radius, double angle) throws IllegalArgumentException{
		
		if(! isValidRadius(radius)){
			throw new IllegalArgumentException("Not a valid radius.");
		}
		setXCoordinate(xCoordinate);
		setYCoordinate(yCoordinate);
		setVelocity(xVelocity,yVelocity);
		this.radius = new Double(radius);
		setAngle(angle);
}





/////////////////
// COORDINATES //
/////////////////

private double xCoordinate;
private double yCoordinate;

/**
 * Returns the x-coordinate of this ship in kilometers.
 * 
 */
@Basic
public double getXCoordinate(){
	return new Double(xCoordinate);
}

/**
 * 
 * @param     xCoordinate
 * 		      The new x-coordinate for this ship.
 * 
 * @post	  The new x-coordinate is equal to the given value.
 * 			| (new this).getXCoordinate() = xCoordinate
 * 			
 * @throws 	  IllegalArgumentException
 * 			| ! isValidCoordinate(xCoordinate)
 */
private void setXCoordinate(double xCoordinate) throws IllegalArgumentException{
	if(! isValidCoordinate(xCoordinate))
		throw new IllegalArgumentException("Illegal x-coordinate");
	this.xCoordinate = new Double(xCoordinate);
}

/**
 * Returns the y-coordinate of this ship in kilometers.
 * 
 */
@Basic
public double getYCoordinate(){
	return new Double(yCoordinate);
}

/**
 * 
 * @param     yCoordinate
 *  	      The new y-coordinate for this ship.
 * 
 * @post	  The new y-coordinate is equal to the given value.
 * 			| (new this).getYCoordinate() = yCoordinate
 * 			
 * @throws 	 IllegalArgumentException
 * 			| ! isValidCoordinate(yCoordinate)
 */
private void setYCoordinate(double yCoordinate)throws IllegalArgumentException{
	if(! isValidCoordinate(yCoordinate))
		throw new IllegalArgumentException("Invalid y-coordinate");
	this.yCoordinate = new Double(yCoordinate);
}

/**
 * Checks whether the given coordinate is valid.
 *
 * @param 	  coordinate
 * 		  	  The coordinate to check.
 * @return    Returns true if the given coordinate is not infinite or max values. 
 * 			| result == ((coordinate != Double.NEGATIVE_INFINITY) && (coordinate != Double.POSITIVE_INFINITY) )
 */
public static boolean isValidCoordinate(double coordinate){
	if(Double.isNaN(coordinate)){
		return false;
	}
	return ((coordinate != Double.NEGATIVE_INFINITY) && (coordinate != Double.POSITIVE_INFINITY) );
}





//////////////
// VELOCITY //
//////////////

private double xVelocity;
private double yVelocity;
private static final double MAX_SPEED = 300000;

/**
 * Returns the velocity of this ship according to the x-axis in km/s.
 *
 */
@Basic 
public double getXVelocity() {
	return new Double(xVelocity);
}

/**
 * Sets the velocity according to the x-axis of this ship to the given value.
 * @param 	xVelocity
 * 			The new value of velocity according to the x-axis.
 * @post    The new velocity is equals to the given value.
 *		  | (new this).getXVelocity = xVelocity
 */		
@Raw
private void setXVelocity(double xVelocity){
	this.xVelocity = new Double(xVelocity);
}

/**
 * Returns the velocity of this ship according to the y-axis in km/s.
 *
 */
@Basic
public double getYVelocity() {
	return new Double(yVelocity);
}

/**
 * Sets the velocity according to the y-axis of this ship to the given value.
 * @param 	yVelocity
 * 			The new value of velocity according to the y-axis.
 * @post    The new velocity is equals to the given value.
 *		  | (new this).getYVelocity = yVelocity
 */		
@Raw
private void setYVelocity(double yVelocity){
	this.yVelocity = new Double(yVelocity);
}

/**
 * Checks whether the given velocity is valid.
 * 
 * @param 	  	  velocity
 * 				  The velocity to be checked.
 * 				
 * @return		  Returns true if the given total velocity is greater than 0 and smaller than MAX_SPEED
 * 				| result == (velocity < -1*MAX_SPEED || velocity > MAX_SPEED)
 */
public static boolean isValidVelocity(double velocity){
	if(Double.isNaN(velocity))
		return false;
	if (velocity < -1*MAX_SPEED || velocity > MAX_SPEED)
		return false;
	return true;
}

/**
 * Sets the velocity of this ship to the given velocities if they are valid, otherwise they are modified to fit the criteria.
 * 
 * @param     xVelocity
 * 		      The new velocity according to the x-axis of this ship.
 * @param     yVelocity
 * 		      The new velocity according to the y-axis of this ship.
 * @post      If the total velocity is smaller than or equal to MAX_SPEED
 * 			  then the velocity according to the x-axis is equal to the xVelocity
 * 			  and the velocity according to the y-axis is equal to the yVelocity.
 * 			| if((Math.sqrt(Math.pow(xVelocity, 2)+Math.pow(yVelocity,2))) <= MAX_SPEED)
 * 			|	then {(new this).getXVelocity() = xVelocity
 * 			|		  (new this).getYVelocity() = yVelocity }
 * @post	  If the total velocity exceeds MAX_SPEED and either of the given velocities is equal to 0, 
 * 			  then other velocity will be set to MAX_SPEED taking their signs(positive or negative) into account. 
 * 			| if ((Math.sqrt(Math.pow(xVelocity, 2)+Math.pow(yVelocity,2))) > MAX_SPEED && (xVelocity == 0 || yVelocity==0))
 * 			|	then {	if(xVelocity == 0)
 *			|				then { (new this).getXVelocity = 0
 *			|						if (yVelocity > 0)
 *			|				        	then (new this).getYVelocity = MAX_SPEED 
 *			|						else
 *			|							then (new this).getYVelocity = MAX_SPEED * -1
 *			|					 }	
 *			|			else {
 *			|					(new this).getYVelocity = 0
 *			|
 *			|					if(xVelocity > 0)
 *			|						then (new this).getXVelocity = MAX_SPEED
 *			|					else
 *			|					    (new this).getXVelocity = MAX_SPEED * -1
 *			|
 *			|			    }
 *			|	}
 *
 * @post      If the total velocity exceeds MAX_SPEED but none of the components are equal to 0 then
 * 			  each component are modified so that the total velocity is equal to MAX_SPEED but the direction
 *            of the total velocity remains the same using method transformVelocities().
 *          | (new this).getXVelocity() = transformVelocities(xVelocity,yVelocity,MAX_SPEED)[0]
 *          | (new this).getYVelocity()	= transformVelocities(xVelocity,yVelocity,MAX_SPEED)[1]					
 */
public void setVelocity(double xVelocity, double yVelocity){
	double[] vel = convertToValidVelocity(xVelocity,yVelocity);
	xVelocity = vel[0];
	yVelocity = vel[1];
	
	double totalVelocity = (Math.sqrt(Math.pow(xVelocity, 2)+Math.pow(yVelocity,2)));
	if(totalVelocity <= MAX_SPEED){
		setXVelocity(xVelocity);
		setYVelocity(yVelocity);
	}
	else if(xVelocity == 0 || yVelocity==0){
		if(xVelocity == 0){
			setXVelocity(0);
			if(yVelocity < 0)
				setYVelocity(-1 *MAX_SPEED);
			else
				setYVelocity(MAX_SPEED);
		}
		else{
			setYVelocity(0);
			if(xVelocity >= 0)
				setXVelocity(MAX_SPEED);
			else
				setXVelocity(MAX_SPEED * -1);
		}
	}
	else {
		double[] vector = transformVelocities(xVelocity,yVelocity,MAX_SPEED);
		setXVelocity(vector[0]);
		setYVelocity(vector[1]);
	}
}

/**
 * Converts the given velocity to a valid velocity.
 * 
 * @param 	  velocity
 * 			  The velocity that has to be converted.
 * @return    If the given velocity is equal to infinity or Double.MAX_VALUE then returns MAX_SPEED.
 * 			  If the given velocity is equal to negative infinity or Double.MIN_VALUE then returns -1 * MAX_SPEED.
 * 			  If the given velocity is not a number return 0.
 * 			| if(Double.isNaN(velocity))
 *		    |    then result == 0
 *	        |  else if(velocity == Double.NEGATIVE_INFINITY || velocity == Double.MIN_VALUE)
 *	 	    |    then result == -1 * MAX_SPEED
 *			|  else if(velocity == Double.POSITIVE_INFINITY || velocity == Double.MAX_VALUE)
 *			|    then result == MAX_SPEED
 */
private double[] convertToValidVelocity(double xVelocity,double yVelocity){
		double velocities[] = { xVelocity, yVelocity };
		int i = 0;
		while (i<=1) {
			if (Double.isNaN(velocities[i])) {
				velocities[i] = 0;
			} else if (velocities[i] == Double.NEGATIVE_INFINITY
					|| velocities[i] == Double.MIN_VALUE) {
				velocities[i] = -1 * MAX_SPEED;
			}

			else if (velocities[i] == Double.POSITIVE_INFINITY
					|| velocities[i] == Double.MAX_VALUE) {
				velocities[i] = MAX_SPEED;
			}
			i++;
		}
		if ((xVelocity == Double.POSITIVE_INFINITY || xVelocity == Double.NEGATIVE_INFINITY)) {
				if (xVelocity == Double.POSITIVE_INFINITY) {
					velocities[0] = MAX_SPEED;
				} 
				else
					velocities[0] = -1 * MAX_SPEED;
				
				if (yVelocity == Double.POSITIVE_INFINITY) {
					velocities[1] = MAX_SPEED;
				} else
					velocities[1] = -1 * MAX_SPEED;
		}
		else if(yVelocity == Double.POSITIVE_INFINITY){
			velocities[0] = 0;
			velocities[1] = MAX_SPEED;
		}
		else if(yVelocity == Double.NEGATIVE_INFINITY){
			velocities[0] = 0;
			velocities[1] = -1* MAX_SPEED;
		}
		return velocities;
	}

/**
 * Transforms the given x- and y-velocity to new x- and y-velocity with the same total direction and of which the total value is equal to the given max.
 * 
 * @param 	 xVelocity
 * 			 The x-component of the velocity.
 * @param 	 yVelocity
 * 			 The y-component of the velocity.
 * @param 	 max
 * 			 The maximum value of the velocity.
 * 
 * @pre		 The given velocities are valid.
 * 		    | isValidVelocity(xVelocity) && isValidVelocity(yVelocity)
 * 		 
 * @return 	 Returns the new velocities with the same direction as the original velocities and of which the total value is equal to the given max.
 * 		    | if(xVelocity > 0)
 * 		    |	then 
 * 	        | 		result[0] ==	Math.abs(xVelocity/yVelocity) * Math.sqrt(Math.pow(max,2)/((Math.abs(xVelocity/yVelocity)*Math.abs(xVelocity/yVelocity)) + 1))
 * 			|	else
 * 			|		result[0] == -1 * (Math.abs(xVelocity/yVelocity) * Math.sqrt(Math.pow(max,2)/((Math.abs(xVelocity/yVelocity)*Math.abs(xVelocity/yVelocity)) + 1)))
 * 			| if(yVelocity > 0)
 * 			|	then 
 * 			|		result[1] == Math.sqrt(Math.pow(max,2)/((Math.abs(xVelocity/yVelocity)*Math.abs(xVelocity/yVelocity)) + 1))
 * 			|	else
 * 			|		result[1] == -1 * (Math.sqrt(Math.pow(max,2)/((Math.abs(xVelocity/yVelocity)*Math.abs(xVelocity/yVelocity)) + 1)))
 */
public static double[] transformVelocities(double xVelocity,double yVelocity,double max){
	assert(isReadyToTransform(xVelocity) && isReadyToTransform(yVelocity));
	double ratio = Math.abs(xVelocity/yVelocity);
	double newYVelocity = Math.sqrt(Math.pow(max,2)/((ratio*ratio) + 1));
	double newXVelocity = ratio * newYVelocity;
	double[] vector = new double[2];
	if(xVelocity < 0)
		vector[0] = (-1 * newXVelocity);
	else
		vector[0] = (newXVelocity);
	if(yVelocity < 0)
		vector[1] = (-1 * newYVelocity);
	
	else
		vector[1] = (newYVelocity);
	return vector;
}





////////////
// RADIUS //
////////////

private final double radius;

/**
 * Returns the radius of this circular ship in km.
 * 
 */
@Basic @Immutable
public double getRadius() {
	return new Double(radius);		
}

/**
 * Checks whether the given radius is valid.
 * 
 * @param 	 radius
 * 			 The radius that has to be checked.		
 * @return	 Returns true if the radius is not equal to infinity or max values and is larger than 10.
 * 			| result == ( (radius != Double.MAX_VALUE) && (radius != Double.MIN_VALUE) 
 *			| && (radius != Double.NEGATIVE_INFINITY) && (radius != Double.POSITIVE_INFINITY) 
 *			| && (radius > 10 ))
 */
public static boolean isValidRadius(double radius){
	if(Double.isNaN(radius))
		return false;
	return ( (radius != Double.MAX_VALUE) && (radius != Double.MIN_VALUE) 
			&& (radius != Double.NEGATIVE_INFINITY) && (radius != Double.POSITIVE_INFINITY) 
			&& (radius > 10));
} 





///////////
// ANGLE //
///////////

private double angle;

/**
 * Returns the angle of this ship in radians.
 *
 */
@Basic
public double getAngle() {
	return new Double(angle);
}

/**
 * Sets the angle of this ship to the given value.
 * 
 * @param 	 angle
 * 			 The new angle of this ship.
 * @pre		 The angle must be greater than or equal to 0 and less than 2*Math.PI.	
 *			| (angle >= 0  && angle < 2*Math.PI)
 * @post      The new angle of this ship is equal to the given 
 *			| (new this).getAngle = angle
 */			
public void setAngle(double angle) {
	assert(angle >= 0  && angle < 2*Math.PI);
	this.angle = new Double(angle);
}

/**
 * Changes the direction of this ship by adding the given angle to the current angle.
 * 
 * @param 	  angle
 * 			  The angle that has to be added to the current angle.
 * @pre 	  The given angle must be greater than 0 and less than 2*Math.PI
 *			| (angle > 0 && angle < 2* Math*PI ) 
 * @post	  The new direction of this ship is equal to the old direction plus the given angle.
 * 			  If old angle plus the given angle exceed 2*Pi then the total angle is reduced to total angle modulo 2*Pi.
 *			| (new this).getAngle() = (getAngle() + angle) % (2*Math.PI)
 * 
 */			
public void addAngle(double angle){
	assert (angle > 0 && angle < 2*Math.PI);
	setAngle( (getAngle() + angle) % (2*Math.PI) );
}





//////////////
// MOVEMENT //
//////////////

/**
 * Changes the position of this ship based on the current position, velocity and a given time duration.
 * 
 * @param 	duration 
 * 			The duration for which the ship is in movement.
 * @throws 	IllegalArgumentException
 * 			The given duration is invalid.
 * 		   | ! isValidDuration (duration)	
 */
public void move(double duration)throws IllegalArgumentException{
	if(! isValidDuration(duration))
		throw new IllegalArgumentException("Invalid duration");
	setXCoordinate(getXVelocity()*duration + getXCoordinate());
	setYCoordinate(getYVelocity()*duration + getYCoordinate());
}

/**
 * Checks whether the given duration is valid.
 * 
 * @param	  duration
 * 		  	  The duration that has to be checked.
 * @return 	  True if the given duration is greater or equal to 0.
 * 		 	| result == ( (duration != Double.NEGATIVE_INFINITY) && (duration != Double.POSITIVE_INFINITY) 
 *			|  && (duration >= 0 ))
 */
public static boolean isValidDuration(double duration){
	if(Double.isNaN(duration))
		return false;
	return ( (duration != Double.NEGATIVE_INFINITY) && (duration != Double.POSITIVE_INFINITY) 
			  && (duration >= 0 ));
}

/**
 * 
 * Changes the velocities of this ship according to the given amount taking this ship's properties 
 * into account.
 * 
 * @param 	  amount
 * 			  The amount that determines the change of speed
 * @effect    If the given amount is negative then the amount is set to 0 and if the amount
 * 			  MAX_SPEED then it is set to MAX_SPEED. The new velocities are then calculated 
 * 			  using the (converted) amount, current velocities and the current angle of the ship. 
 * 			| 	if(Double.isNaN(amount))
 *			|		then amount = 0;
 *			|	else if(amount < 0 || amount == Double.NEGATIVE_INFINITY || amount == Double.MIN_VALUE)
 *			|		then amount = 0;
 *			|	else if (amount == Double.POSITIVE_INFINITY || amount == Double.MAX_VALUE || amount > MAX_SPEED)
 *			|		then amount = MAX_SPEED;
 *			|	setVelocity(this.getXVelocity() + amount * Math.cos(this.getAngle()), this.getYVelocity() + amount * Math.sin(this.getAngle()));
 * 			
 */	
public void thrust(double amount){
	if(Double.isNaN(amount)){
		amount = 0;
	}
	else if(amount < 0 || amount == Double.NEGATIVE_INFINITY || amount == Double.MIN_VALUE)
		amount = 0;
	else if (amount == Double.POSITIVE_INFINITY || amount == Double.MAX_VALUE || amount > MAX_SPEED)
		amount = MAX_SPEED;
	double newXVelocity = this.getXVelocity() + amount * Math.cos(this.getAngle());
	double newYVelocity = this.getYVelocity() + amount * Math.sin(this.getAngle());
	this.setVelocity(newXVelocity, newYVelocity);
}

/**
 * 
 * Returns the distance between the given ship and this ship.
 * 
 * @param		  ship
 * 				  The ship with which the distance from this ship should be calculated.
 * @return		  Returns the distance between the given ship and this ship. The distance 
 * 				  is 0 if the given ship is this ship and negative if the given ship and 
 * 				  this ship overlap.
 * 				| if(ship == this)
 *				|		then result == 0;
 *				| else {
 *				|  		result == Math.sqrt(Math.pow((ship.getXCoordinate()-this.getXCoordinate()),2)
 *				|	             -Math.pow((ship.getYCoordinate()-this.getYCoordinate()),2))
 *				|  				 -(ship.getRadius()+ this.getRadius())
 *				| }
 * @throws		  Throws IllegalArgumentException if the given ship is invalid.	
 * 				| (!isValidShip(ship))
 * 					
 */
public double getDistanceBetween(Ship ship) throws IllegalArgumentException{
	if(!isValidShip(ship))
		throw new IllegalArgumentException("Invalid Ship, NullPointer");
	if(ship == this)
		return 0;
	double xCoordinateNewShip = ship.getXCoordinate();
	double xCoordinateThisShip = this.getXCoordinate();
	double yCoordinateNewShip = ship.getYCoordinate();
	double yCoordinateThisShip = this.getYCoordinate();
	double distanceBetweenCenters = Math.sqrt(Math.pow((xCoordinateNewShip-xCoordinateThisShip),2)
					  +Math.pow((yCoordinateNewShip-yCoordinateThisShip),2));
	double distanceBetweenShips = distanceBetweenCenters - (ship.getRadius()+ this.getRadius());
	return distanceBetweenShips;
}

/**
 * 
 * Checks if the given ship and this ship overlap.
 * 
 * @param 		  ship
 * 				  The ship with which this ship should be compared to see if they overlap.
 * 
 * @return		  Returns true if this ship overlaps with the given ship or if the given ship is 
 * 				  equal to this ship.
 * 				| result == (getDistanceBetween < 0) || (this == ship)
 * @throws		  IllegalArgumentException
 * 				  Throws IllegalArgumentException if the given ship is invalid.	
 * 				| (!isValidShip(ship)) 	
 */
public boolean overlap(Ship ship) throws IllegalArgumentException{
	if(!isValidShip(ship))
		throw new IllegalArgumentException("Invalid Ship, NullPointer");
	if(ship == this)
		return true;
	if(getDistanceBetween(ship) < 0)
		return true;
	else 
		return false;
	
}

/**
 * 
 * Calculates the time in seconds in which the given ship and this ship will collide.
 * 
 * @param 		  ship
 * 				  The ship with which the time to collision is calculated.
 * @return		  Returns the time in seconds  in which the given ship and this ship collide if they ever collide.
 * 				  Returns Double.POSITIVE_INFINITY if the given ship and this ship never collide.
 * 				| let
 * 				| 	deltaR = {(ship.getXCoordinate()- this.getXCoordinate()),(ship.getYCoordinate() - this.getYCoordinate())}; 
 *				| 	deltaV = { (ship.getXVelocity() - this.getXVelocity()), (ship.getYVelocity() - this.getYVelocity())};
 *				|	deltaRR = dotProduct(deltaR,deltaR);
 *				|	deltaVV = dotProduct(deltaV,deltaV);
 *				|	deltaVR = dotProduct(deltaV,deltaR);
 *				|	double parameterD = (Math.pow(deltaVR,2) - deltaVV)*(deltaRR - Math.pow((this.getRadius()+ship.getRadius()),2));  
 * 				| in
 * 				|  if(parameterD <= 0 || deltaVR >=0)
 * 				|  		then result == Double.POSITIVE_INFINITY
 * 				|	else
 * 				|       result == - ((deltaVR + Math.sqrt(parameterD))/deltaVV)    
 * 
 * @throws 		  IllegalArgumentException
 * 				  Throws IllegalArgumentException if the given ship is invalid.
 * 				| !isValidShip(ship)	
 */
public double getTimeToCollision(Ship ship) throws IllegalArgumentException{
	if(!isValidShip(ship))
		throw new IllegalArgumentException("Invalid Ship, NullPointer");
	double[] deltaR = {(ship.getXCoordinate()- this.getXCoordinate()),(ship.getYCoordinate() - this.getYCoordinate())}; 
	double[] deltaV = { (ship.getXVelocity() - this.getXVelocity()), (ship.getYVelocity() - this.getYVelocity())};
	double deltaRR = dotProduct(deltaR,deltaR);
	double deltaVV = dotProduct(deltaV,deltaV);
	double deltaVR = dotProduct(deltaV,deltaR);
	double parameterD = Math.pow(deltaVR,2) - (deltaVV)*(deltaRR - Math.pow((this.getRadius()+ship.getRadius()),2));  
	if(parameterD <= 0 || deltaVR >=0)
		return Double.POSITIVE_INFINITY;
	else 
		return - ((deltaVR + Math.sqrt(parameterD))/deltaVV);
		
}

/**
 * 
 * Give the dot product of two given arrays of length equal to 2.
 * 
 * @param 	 	  vector1
 * 				  The first array of length 2. 
 * @param 		  vector2
 * 				  The second array of length 2.
 * @pre 		  The given arrays must not be null.
 * 				| (vector1 != null && vector2 != null)
 * @pre           The length of the given arrays must be 2.
 * 				| (vector1.length == 2 && vector2.length == 2)
 * @pre			  The elements of the arrays must not be null.
 * 				| !(Double.isNaN(vector1[0])) && !(Double.isNaN(vector1[1])) &&
 * 				| !(Double.isNaN(vector2[0])) && !(Double.isNaN(vector2[1]))
 * 
 * @return		  Returns the dot product of given arrays.
 * 				| result == vector1[0]*vector2[0]+vector1[1]*vector2[1]
 */			
public double dotProduct(double[] vector1, double[] vector2){
	assert(vector1 != null && vector2 != null && vector1.length == 2 && vector2.length == 2 && 
			!(Double.isNaN(vector1[0])) && !(Double.isNaN(vector1[1])) && !(Double.isNaN(vector2[0]))
			&& !(Double.isNaN(vector2[1])) );
	return (vector1[0]*vector2[0]+vector1[1]*vector2[1]);
}

/**
 * 
 * Calculates the collision position between the given ship and this ship.
 * 
 * @param 		ship
 * 		  		The ship with which the collision position is to be calculated.
 * 
 * @return		Returns the collision position as an array of doubles with an x- and y-coordinate, if the two ships ever collide, otherwise null.
 * 		  	  | if(this.getTimeToCollision(ship) == Double.POSITIVE_INFINITY
 * 			  |		then result == null
 *			  |	else 
 * 			  |		let
 * 			  |			colThis = (getCollisionCooridnate(this,collisionTime));
 *			  |			colShip = (getCollisionCooridnate(ship,collisionTime));
 * 			  |			angle = Math.atan((ship.getYCoordinate() + this.getTimeToCollision(ship)*ship.getYVelocity() 
 * 			  |					- this.getYCoordinate() + this.getTimeToCollision(ship)*this.getYVelocity())
 * 			  |					/ (this.getXCoordinate() + this.getTimeToCollision(ship)*this.getXVelocity()
 * 			  |					- this.getXCoordinate() + this.getTimeToCollision(ship)*this.getXVelocity()))
 * 			  |		in
 * 			  |			if(angle != 0){
 * 			  |				if((colShip[0]- colThis[0]) < 0){
 *			  |					result[0] == (colThis[0] - Math.cos(angle) * this.getRadius());
 *			  |					result[1] == (colThis[1]- Math.sin(angle) * this.getRadius());
 *			  |				}
 *			  |				else {
 *			  |					result[0] == (colThis[0] + Math.cos(angle) * this.getRadius());
 *			  |					result[1] == (colThis[1] + Math.sin(angle) * this.getRadius());
 *			  |				}
 *			  |			}
 *			  |			else{
 *			  |				if(colThis[1] < colShip[1]){
 *			  |					result[0] == (colThis[0]);
 *			  |					result[1] == (colThis[1] + this.getRadius());
 *			  |				}
 *			  |				else {
 *			  |					result[0] == (colThis[0]);
 *			  |					result[1] == (colThis[1] - this.getRadius());
 *			  |				}
 *			  |			}
 * @throws 		IllegalArgumentException
 * 				Throws IllegalArgumentException if the given ship is invalid.
 * 			  | !isValidShip(ship)
 */		
public double[] getCollisionPosition(Ship ship) throws IllegalArgumentException {
	if(!isValidShip(ship))
	throw new IllegalArgumentException("Invalid Ship, NullPointer");
	double collisionTime = this.getTimeToCollision(ship);
	if(collisionTime == Double.POSITIVE_INFINITY || this.overlap(ship))
		return null;
	double[] colThis = (getCollisionCooridnate(this,collisionTime));
	double[] colShip = (getCollisionCooridnate(ship,collisionTime));
	if ( colThis[1] == colShip[1]){
		double[] collisionPosition = new double[2];
		if(colShip[0] > colThis[0]){
			collisionPosition[0] = (colThis[0]+this.getRadius());
			collisionPosition[1] = colThis[1];
		}
		else{
			collisionPosition[0] = (colThis[0]-this.getRadius());
			collisionPosition[1] = colThis[1];
		}
		return collisionPosition;
	}
	double angle =  Math.atan((colShip[1]-colThis[1])/(colShip[0]- colThis[0]));
	double[] collisionPosition = new double[2];
	if (angle != 0) {
		double xChange = Math.cos(angle) * this.getRadius();
		double yChange = Math.sin(angle) * this.getRadius() ;
		if((colShip[0]- colThis[0]) < 0){
			collisionPosition[0] = (colThis[0] - xChange);
			collisionPosition[1] = (colThis[1] - yChange);
		}
		else {
			collisionPosition[0] = (colThis[0] + xChange);
			collisionPosition[1] = (colThis[1] + yChange);
		}
	}
	else {
		if(colThis[1] < colShip[1]){
			collisionPosition[0] = (colThis[0]);
			collisionPosition[1] = (colThis[1] + this.getRadius());
		}
		else {
			collisionPosition[0] = (colThis[0]);
			collisionPosition[1] = (colThis[1] - this.getRadius());
		}
	}
	
return collisionPosition;
}

/**
 * 
 * Returns the collision position of the center of the given ship, given the time in which it will collide.
 * 
 * @param 		  ship
 * 				  Ship of which the collision position should be calculated.
 * @param 		  duration
 * 				  The time in which the ship is going to collide.
 * @pre			  ship should be valid.
 * 				| (ship != null)
 * @pre 		  duration should be valid.
 * 				| isValidDuration(duration) 
 * @return		  Returns the position in which this ship will collide.
 * 				| result == { ship.getXCoordinate() + duration*ship.getXVelocity() 
 * 				|			, ship.getYCoordinate() + duration*ship.getYVelocity()}
 * 
 * 
 */
public double[] getCollisionCooridnate(Ship ship, double duration){
	double[] collisionCoordinate = { ship.getXCoordinate() + duration*ship.getXVelocity() , ship.getYCoordinate() + duration*ship.getYVelocity()};
	return collisionCoordinate;
}

/**
 * 
 * Checks whether the given ship is valid.
 * 
 * @param 		  ship
 * 				  The ship that has to be checked.
 * 
 * @return		  Returns false if the given ship is null.
 * 				| result == (ship != null)
 * 
 */
public static boolean isValidShip(Ship ship){
	if(ship == null)
		return false;
	return true;
}


/**
 * Checks whether the given velocity is valid.
 * 
 * @param 	  	  velocity
 * 				  The velocity to be checked.
 * 				
 * @return		  Returns true if the given total velocity is not infinity and not NaN.
 * 				| result != (Double.isNaN(velocity) || velocity==Double.POSITIVE_INFINITY  || velocity == Double.NEGATIVE_INFINITY || velocity == 0)
 */
public static boolean isReadyToTransform(double velocity){
	if(Double.isNaN(velocity) || velocity==Double.POSITIVE_INFINITY  || velocity == Double.NEGATIVE_INFINITY || velocity == 0)
		return false;
	return true;
}




}


